/*
 *  include/clinux/sched.h
 *
 *  last modified at 2007.07.15 00:33 by ChenJie
 *
 */

#ifndef SCHED_H
#define SCHED_H

#include <clinux/config.h>
#include <clinux/kernel.h>

//进程运行可能处的状态：
#define TASK_RUNNING		1		//正在运行，或就绪
#define TASK_INTERRUPTIBLE	2		//
#define TASK_UNINTERRUPTIBLE	3		//任务等待IO操作
#define TASK_ZOMBIE		4		//
#define TASK_STOPPED		5		//任务已停止

//进程运行初始时间片：
#define TASK_INIT_COUNTER	15

//进程优先级：
#define TASK_KERNEL_PRIORITY	5

#define TASK0_TSS_ENTRY		4
#define TASK0_LDT_ENTRY		(TASK0_TSS_ENTRY+1)

/*
 * 任务n的TSS段描述符在GDT中的表项
 */
#define TASK_TSS_ENTRY(n)	((n)*2 + TASK0_TSS_ENTRY)
/*
 * 任务n的LDT段描述符在GDT中的表项
 */
#define TASK_LDT_ENTRY(n)	((n)*2 + TASK0_LDT_ENTRY)
/*
 * 任务n的TSS选择子
 */
#define TASK_TSS_SELECTOR(n)	(TASK_TSS_ENTRY(n)<<3)
/*
 * 任务n的LDT选择子
 */
#define TASK_LDT_SELECTOR(n)	(TASK_LDT_ENTRY(n)<<3)

//i387结构:
struct i387_struct {
	unsigned long	cwd;		//控制字(Control word)
	unsigned long	swd;		//状态字(Status word)
	unsigned long	twd;
	unsigned long	fip;
	unsigned long	fcs;
	unsigned long	foo;
	unsigned long	fos;
	unsigned long	st_space[20];
};

//TSS结构：
struct tss_struct {
	unsigned long	back_link;	//高字为0
	unsigned long	esp0;
	unsigned long	ss0;		//高定为0
	unsigned long	esp1;
	unsigned long	ss1;		//高字为0
	unsigned long	esp2;
	unsigned long	ss2;		//高字为0
	unsigned long	cr3;
	unsigned long	eip;
	unsigned long	eflags;
	unsigned long	eax;
	unsigned long 	ecx;
	unsigned long 	edx;
	unsigned long	ebx;
	unsigned long	esp;
	unsigned long	ebp;
	unsigned long	esi;
	unsigned long	edi;
	unsigned long	es;		//高字为0
	unsigned long	cs;		//高字为0
	unsigned long	ss;		//高字为0
	unsigned long	ds;		//高字为0
	unsigned long	fs;		//高字为0
	unsigned long	gs;		//高字为0
	unsigned long	ldt;		//高字为0
	unsigned long	trace_bitmap;	
	struct i387_struct i387;
};
	
struct task_struct {
	//局部描述表(LDT)
	struct desc_struct	ldt[4];
	//任务状态段(TSS)
	struct tss_struct 	tss;

	//基本信息：
	long	state;		//进程当前状态
	long	counter;	//运行时间片
	long	priority;	//运行优先数

	int	exit_code;	//退出码, 父进程取

	long	pid;		//进程号
	long	father;		//父进程号
	
	long	utime;		//用户态运行时间(滴答数)
	long	stime;		//系统态运行时间(滴答数)
	long 	cutime;		//子进程用户态运行时间(滴答数)
	long	cstime;		//子进程系统态运行时间(滴答数)

	unsigned long start_time; //进程开始时刻

	unsigned short used_math; //是否使用数学协处理器

};

union task_union {
	struct task_struct task;	//task
	unsigned long kernel_stack[1024]; //kernel_stack
};

//初始任务：
extern union task_union init_task;
//任务数组：
extern struct task_struct * task[NR_TASKS];
//当前运行任务：
extern struct task_struct * current_task;
//最近一次使用协处理器的任务的指针:
extern struct task_struct * last_task_used_math;
//系统当前滴答数:
extern unsigned long volatile jiffies;
//系统上一次分配的进程号:
extern long last_pid;

//进程调度：
void schedule(void);
void do_timer(void);
void sched_init(void);

/*
 * 功能:
 * 	切换到任务 n
 * 输入:
 * 	n	目标任务的标识号
 * 输出:
 * 	无
 * 全局变量:
 * 	task
 * 	current_task
 * 处理说明:
 * 	1.切换时机是在ring0级, 切换后原任务tss动态字段内容是ring0的上下文.
 * 	  但目标任务初次被切换运行时, 其动态字段的初始内容是fork系统调用时的
 * 	  ring3 的上下文.
 * 	2.任务切换前要指定current_task为目标任务.
 * 	3.切换出的目标任务的运行状态分两种情况:
 * 		(1)目标任务的tss动态字段是由fork设定.此时返回点在fork调用的下
 * 		   一条指令, 运行级为ring3.
 * 		(2)目标任务的tss动态字段是因任务切换自动更新.此时返回点在
 * 		   task_switch_to函数的任务切换的下一指令, 运行级为ring0.
 */
static inline void  task_switch_to(int n)
{
	unsigned long new_task_addr[2];
	if(task[n]==current_task)
		return;
	current_task = task[n];
	new_task_addr[1] = TASK_TSS_SELECTOR(n);
	__asm__("ljmp *%0"::"m"(*new_task_addr));
}



#endif // SCHED_H
